﻿using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Newtonsoft.Json;
using System.Xml;
using WqLunTan.Models;
using WqLunTan.DBContext;
using WqLunTan.Extensions;
using WqLunTan.Reply;
using System.Globalization;
using Microsoft.EntityFrameworkCore;
using WqLunTan.Models.DataBase;
using Microsoft.AspNetCore.Http;

namespace WqLunTan.Controllers
{
    /// <summary>
    /// 微信回调接口
    /// </summary>
    public class WxApiController : BaseController
    {
        /// <summary>
        /// 保存当前请求的域名
        /// </summary>
        public static string CurrentDomain { get; set; } = "获取域名失败";

        /// <summary>
        /// 被动回复文本消息
        /// </summary>
        /// <returns></returns>
        public async Task<IActionResult> Sendmsg(string signature, string timestamp, string nonce, string echostr)
        {
            if (!string.IsNullOrWhiteSpace(echostr))
            {
                return Content(echostr);    // 验证Url
            }

            CurrentDomain = Request.GetCurrentDomain();
            var reply = string.Empty;
            var ireplys = HttpContext.RequestServices.GetServices<IReply>();
            IReply ireply;
            var env = HttpContext.RequestServices.GetService<IHostingEnvironment>();
            var errpath = Path.Combine(env.WebRootPath, "applog", "errorlog.txt");
            var datapath = Path.Combine(env.WebRootPath, "applog", "datalog.txt");
            var fi = new FileInfo(errpath);
            if (!fi.Directory.Exists)
            {
                fi.Directory.Create();
            }

            try
            {
                if (Request.Body.CanRead)
                {
                    var sr = new StreamReader(Request.Body);
                    var stream = await sr.ReadToEndAsync();
                    if (!string.IsNullOrWhiteSpace(stream))
                    {
                        var doc = new XmlDocument();
                        doc.LoadXml(stream);
                        var data = new wechat_data();
                        var node = doc.GetElementsByTagName("MsgType").Item(0);
                        if (Enum.TryParse<MsgType>(node.InnerText, out var msgType))
                        {
                            // <xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>12345678</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[你好]]></Content></xml>
                            // <xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>12345678</CreateTime><MsgType><![CDATA[news]]></MsgType><ArticleCount>2</ArticleCount><Articles><item><Title><![CDATA[title1]]></Title><Description><![CDATA[description1]]></Description><PicUrl><![CDATA[picurl]]></PicUrl><Url><![CDATA[url]]></Url></item><item><Title><![CDATA[title]]></Title><Description><![CDATA[description]]></Description><PicUrl><![CDATA[picurl]]></PicUrl><Url><![CDATA[url]]></Url></item></Articles></xml>
                            data.MsgType = msgType;
                            var sid = doc.GetElementsByTagName("MsgId").Count > 0 ? doc.GetElementsByTagName("MsgId").Item(0).InnerText : string.Empty;
                            if (long.TryParse(sid, out var msgid))
                            {
                                data.MsgID = msgid;
                            }
                            data.ToUserName = doc.GetElementsByTagName("ToUserName").Item(0).InnerText;
                            data.FromUserName = doc.GetElementsByTagName("FromUserName").Item(0).InnerText;
                            if (long.TryParse(doc.GetElementsByTagName("CreateTime").Item(0).InnerText, out var ctime))
                            {
                                data.CreateTime = ctime;
                                var unixTime = new DateTimeOffset(1970, 1, 1, 0, 0, 0, 0, TimeSpan.Zero);
                                data.CreateTimeUtc = unixTime.AddSeconds(ctime);
                            }
                            var imps = ReplyImplDict.getIReplyProvider();

                            switch (msgType)
                            {
                                case MsgType.text:
                                    // 微信文本消息
                                    data.Content = doc.GetElementsByTagName("Content").Item(0).InnerText;

                                    // 从集合的key 查找符合条件的命令
                                    foreach (var key in imps.Keys)
                                    {
                                        if (data.Content.StartsWith(key, true, CultureInfo.InvariantCulture))
                                        {
                                            ireply = ireplys.FirstOrDefault(x => x.GetType().Name.Equals(imps[key]));
                                            if (ireply != null)
                                            {
                                                reply = ireply.reply(data);    // 处理回复消息
                                            }
                                        }
                                    }
                                    break;
                                case MsgType.@event:
                                    // 微信事件消息
                                    data.Event = doc.GetElementsByTagName("Event").Item(0).InnerText.ToLower();
                                    data.EventKey = doc.GetElementsByTagName("EventKey").Item(0).InnerText;
                                    data.Ticket = doc.GetElementsByTagName("Ticket").Count > 0 ? doc.GetElementsByTagName("Ticket").Item(0).InnerText : string.Empty;

                                    if (data.Event.Equals("subscribe"))
                                    {
                                        var wcoi = await DbContext.WeChatOpenId.Where(x => x.openid.Equals(data.FromUserName)).FirstOrDefaultAsync();
                                        if (wcoi != null)
                                        {
                                            wcoi.status = true;
                                            wcoi.last_update = DateTimeOffset.UtcNow;
                                            await DbContext.SaveChangesAsync(); // 重新关注
                                        }
                                        else
                                        {
                                            DbContext.WeChatOpenId.Add(new wechat_openid() { openid = data.FromUserName, status = true, create_time = DateTimeOffset.UtcNow, last_update = DateTimeOffset.UtcNow });
                                            await DbContext.SaveChangesAsync(); // 第一次关注
                                        }
                                    }
                                    else if (data.Event.Equals("scan"))
                                    {
                                        // 关注后再次扫码
                                    }
                                    else if (data.Event.Equals("unsubscribe", StringComparison.InvariantCultureIgnoreCase))
                                    {
                                        // 取消订阅
                                        var wcoi = await DbContext.WeChatOpenId.Where(x => x.openid.Equals(data.FromUserName)).FirstOrDefaultAsync();
                                        if (wcoi != null)
                                        {
                                            wcoi.status = false;
                                            wcoi.last_update = DateTimeOffset.UtcNow;
                                            await DbContext.SaveChangesAsync();
                                        }
                                    }

                                    ireply = ireplys.FirstOrDefault(x => x.GetType().Name.Equals(imps[data.Event]));
                                    if (ireply != null)
                                    {
                                        reply = ireply.reply(data);    // 处理回复消息
                                    }
                                    break;
                                default:
                                    ireply = ireplys.FirstOrDefault(x => x.GetType().Name.Equals(nameof(NormalReply)));
                                    reply = ireply.reply(data);  // 回复功能列表
                                    break;
                            }
                        }

                        if (data.MsgID > 0)
                        {
                            //await System.IO.File.AppendAllTextAsync(datapath, stream);
                            //await System.IO.File.AppendAllTextAsync(datapath, JsonConvert.SerializeObject(data));
                            data.NotNullStrings();
                            DbContext.Database.BeginTransaction();
                            DbContext.WeChatData.Add(data);     // 事件消息 消息ID为0, 不保存到数据库
                            await DbContext.SaveChangesAsync(); // 保存微信消息到数据库
                            var wechatUser = await DbContext.WeChatOpenId.Where(x => x.openid.Equals(data.FromUserName)).SingleOrDefaultAsync();

                            if (string.IsNullOrWhiteSpace(reply))
                            {
                                ireply = ireplys.FirstOrDefault(x => x.GetType().Name.Equals(nameof(SubscribeReply)));
                                reply = ireply.reply(data);  // 回复功能列表
                            }

                            // 回复消息的处理方式
                            var replyMessage = DbContext.WeChatReply.Where(x => x.openid.Equals(data.FromUserName) && x.is_send == false).FirstOrDefault();
                            if (replyMessage != null)
                            {
                                var IreplyMsg = HttpContext.RequestServices.GetServices<IReply>().Where(x => x.GetType().Name.Equals(nameof(MessageReply))).FirstOrDefault();
                                if (IreplyMsg != null)
                                {
                                    var dataJson = JsonConvert.SerializeObject(data);
                                    var dataCopy = JsonConvert.DeserializeObject<wechat_data>(dataJson);
                                    dataCopy.Content = replyMessage.content;
                                    reply = IreplyMsg.reply(dataCopy);
                                    replyMessage.is_send = true;
                                    replyMessage.last_update = DateTimeOffset.UtcNow;
                                }
                                wechatUser.ut_message = 0;  // 未读消息归零
                            }

                            ++wechatUser.ut_message;
                            wechatUser.last_update = DateTimeOffset.UtcNow;
                            await DbContext.SaveChangesAsync();
                            DbContext.Database.CommitTransaction();

                            return Content(reply);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                DbContext.Database.RollbackTransaction();
                var err = ex;
                while (err.InnerException != null)
                {
                    err = err.InnerException;
                }
                await System.IO.File.AppendAllTextAsync(errpath, $"{err.Message}\r\n{err.StackTrace}");
            }
            // 出现异常, 暂时没办法处理, 或者消息id重复
            return Content(reply);
        }
    }
}
